package io.noties.markwon.app.sample;

import com.noties.markwon.annotation.NonNull;
import com.noties.markwon.annotation.Nullable;
import com.noties.markwon.utils.TextUtils;

import io.noties.markwon.app.utils.Cancellable;
import io.noties.markwon.app.utils.SampleUtils;
import io.noties.markwon.sample.annotations.MarkwonArtifact;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import ohos.app.Context;

/**
 * @author: yangrui
 * @function: SampleManager
 * @date: 2021/3/23
 */
public class SampleManager {
    private final ExecutorService executorService;

    private final List<Sample> samples = new ArrayList<>();

    public SampleManager(Context context, ExecutorService executorService) {
        this.executorService = executorService;
        samples.addAll(SampleUtils.readSamples(context));
    }

    @Nullable
    public final Sample sample(@NonNull String id) {
        return samples.stream().filter(it -> it.getId() == id).findFirst().orElse(null);
    }

    public Cancellable samples(SampleSearch search, final Callback callback) {
        Future<?> future = executorService.submit(() -> {
            List<Sample> source;
            if (search instanceof SampleSearch.Artifact) {
                source = samples.stream()
                        .filter(it -> it.getArtifacts().contains(((SampleSearch.Artifact) search).getArtifact()))
                        .collect(Collectors.toList());
            } else if (search instanceof SampleSearch.Tag) {
                source = samples.stream()
                        .filter(it -> it.getTags().contains(((SampleSearch.Tag) search).getTag()))
                        .collect(Collectors.toList());
            } else {
                source = samples;
            }

            final String text = search.getText();
            List<Sample> results;
            if (TextUtils.isEmpty(text)) {
                results = source;
            } else {
                results = source.stream()
                        .filter(it -> filter(it, text))
                        .collect(Collectors.toList());
            }
            if (callback != null) {
                callback.callback(results);
            }
        });

        Cancellable cancellable = new Cancellable() {
            @Override
            public void cancel() {
                future.cancel(true);
            }

            @Override
            public boolean isCancelled() {
                return future.isDone();
            }
        };

        return cancellable;
    }

    private boolean filter(Sample sample, String text) {

        return TextUtils.contains(sample.getJavaClassName(), text, true)
                || TextUtils.contains(sample.getTitle(), text, true)
                || TextUtils.contains(sample.getDescription(), text, true)
                || filterTags(sample.getTags(), text)
                || filterArtifacts(sample.getArtifacts(), text);
    }

    private boolean filterTags(List<String> tags, String text) {
        return tags.stream().filter(it -> TextUtils.contains(it, text, true)).findFirst().orElse(null) != null;
    }

    private boolean filterArtifacts(List<MarkwonArtifact> artifacts, String text) {
        return artifacts.stream().filter(it -> TextUtils.contains(it.artifactName(), text, true)).findFirst().orElse(null) != null;
    }


    public interface Callback {
        /**
         * item search by tag list obtain new list
         *
         * @param samples filter tag callback
         */
        void callback(List<Sample> samples);
    }
}
